#ifndef RING_QUEUE
#define RING_QUEUE

#include <iostream>
#include <pthread.h>
#include <vector>
#include "Sem.hpp"

const int g_defalut_N = 5;

template<class T>
class RingQueue{
public:
    RingQueue(int defalut_N = g_defalut_N):
    _queue(defalut_N),_N(defalut_N),
    _space(defalut_N),_data(0),
    _pi(0),_ci(0)
    {
        //初始化锁
        pthread_mutex_init(&_cmutx,nullptr);
        pthread_mutex_init(&_pmutx,nullptr);
    }
    ~RingQueue()
    {
        pthread_mutex_destroy(&_cmutx);
        pthread_mutex_destroy(&_pmutx);
    }

    void Push(const T& in)
    {
        //取空间
        //在多个生产者间：
        //就像是电影买票，先给所有线程取了(买票)，再访问存储数据的数组（排队入场）
        _space.p();
        //在多个生产消费者的模型中
        //需要控制多个生产者间的线程，所以需要加锁形成互斥关系
        pthread_mutex_lock(&_pmutx);
        _queue[_pi++] = in;
        //取余，保证循环
        _pi %= _N;
        pthread_mutex_unlock(&_pmutx);
        //给data空间
        _data.v();
    }

    void Pop(T& out)
    {
        //取data空间
        _data.p();
        pthread_mutex_lock(&_cmutx);
        out = _queue[_ci++];
        _ci %= _N;
        pthread_mutex_unlock(&_cmutx);
        //放空间
        _space.v();
    }


private:
    std::vector<T> _queue;
    int _N;
    //信号量，一个代表空间资源，一个代表存入的数据资源
    Sem _space;
    Sem _data;
    //消费者和生产者在数组中的下标
    int _pi;
    int _ci;
    //消费者和消费者间的锁，生产者和生产者中的锁
    pthread_mutex_t _cmutx;
    pthread_mutex_t _pmutx;
};

#endif